package com.aispeech.asr.webase.config.error;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.reactivestreams.Publisher;
import org.springframework.core.ResolvableType;
import org.springframework.http.MediaType;
import org.springframework.http.ReactiveHttpOutputMessage;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import java.util.Collections;
import java.util.List;
import java.util.Map;

@Component
@Slf4j
public class JsonHttpMessageWriter implements HttpMessageWriter<Map<String, Object>> {
    private static final String ERROR_FORMAT = "{\"errno\":%d,\"error\":\"%s\",\"data\":null}";

    @Override
    public List<MediaType> getWritableMediaTypes() {
        return Collections.singletonList(MediaType.APPLICATION_JSON);
    }

    @Override
    public boolean canWrite(ResolvableType resolvableType, MediaType mediaType) {
        return MediaType.APPLICATION_JSON.includes(mediaType);
    }

    @Override
    public Mono<Void> write(
            Publisher<? extends Map<String, Object>> publisher,
            ResolvableType resolvableType, MediaType mediaType,
            ReactiveHttpOutputMessage message, Map<String, Object> map) {
        return Mono.from(publisher)
                .flatMap(m -> message.writeWith(
                        Mono.just(message
                                .bufferFactory()
                                .wrap(transform2Json(m).getBytes()))));

    }

    private String transform2Json(Map<String, Object> sourceMap) {
        String message = (String) sourceMap.get("message");
        if (StringUtils.isNotEmpty(message)) {
            message = message.replaceAll("\"", "\\\"");
        } else {
            message = "Internal Error";
        }

        String error = String.format(ERROR_FORMAT, sourceMap.getOrDefault("code", 500), message);

        return error;
    }
}
